#!/usr/bin/wish -f ## ##+####################################################################### ## NOTE: ## If the 'wish' interpreter is in another directory, like ## /usr/local/bin, you, as root, can make a soft-link from 'wish' there ## to /usr/bin/wish --- with a command like ## ln -s /usr/bin/local/wish /usr/bin/wish ## The form of this command: ## ln -s ##+####################################################################### ## Tk SCRIPT NAME: tkAngleConvertSelect_radians-degrees-percents.tk ## ##+####################################################################### ## PURPOSE: This TkGUI script provides a GUI for showing angles between ## 0 and 360 degrees in three different units: ## - degrees ## - radians ## - percents of the circumference of a circle. ## ## These 3 different units are shown (and selected for conversion) ## via 3 'sliders' of 3 Tk 'scale' widgets. ## ## These 3 different (corresponding) numbers are also shown ## in 3 'text' widgets, a few characters wide --- from which ## a user can copy-and-paste the numbers from this GUI window ## to some other window. ## ## For any 'slider' change, this GUI script IMMEDIATELY ## updates the location of the other 2 'sliders' --- and ## the current angle is depicted on a circle drawn ## in a 'canvas' wdiget in a corner of the GUI ## window (covering about 20% of the window). ## ## The 3 text widgets showing the angle in the 3 different units, ## are also IMMEDIATELY updated whenever any one of the 3 ## scale widget 'sliders' is changed. ## ## By clicking on a 'UseIt' button on the GUI, this script ## returns a string containing the current angle (in the ## 3 different units) to a calling script/application. ## ## This script sill accept an angle (in degrees) which is ## used to initialize the ## - setting of the 3 'sliders' ## - the numbers shown in the 3 small text widgets ## - the display of an angle in a circle on the canvas widget. ## ## SOME USES: ## ## 1) Useful for helping math-science students get a visual ## 'feel' for the relation between radians and degrees and ## the distance around the circumference of a circle. ## ## 2) Also could be useful for programmers (ex: Tcl-Tk programmers) ## for determining angles (example: in radians) to be used in ## various Tcl-Tk apps --- example: Tk apps doing 'create arc' ## commands on a Tk 'canvas'. ## ## 3) IN A SHELL SCRIPT OR ANOTHER TK SCRIPT, this Tk script can ## ACT AS AN ANGLE SELECTOR by passing the current angle (in ## the 3 different units) to stdout, when the OK/UseIt button ## is clicked. ## Example output string: 180.0 3.14159 0.5 ## ##+######################################################################## ## 'CANONICAL' STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (win-name, win-position, win-color-scheme, ## fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc). ## 1a) Define ALL frames (and sub-frames). ## 1b) Pack ALL the frames and sub-frames. ## 2) Define & pack all widgets in the frames, frame by frame. ## ## 3) Define key and mouse/touchpad/touch-sensitive-screen 'event' ## BINDINGS, if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI INITIALIZATION (typically with one or two ## procs in section 4), if needed. ## ##+################################# ## The code structure in more detail, for this particular script: ## ## 1a) Define ALL frames: ## Top-level : 'fRsliders', 'fRdepict' , 'fRbuttons' ## Sub-frames: 'fRsliders.fRdeg', 'fRsliders.fRrad', 'fRsliders.fRpcnt' ## ## 'fRsliders' and 'fRdepict' are to be on the top of the GUI, ## on the left and right, respectively. ## 'fRbuttons' is to be on the bottom of the GUI. ## ## 1b) Pack ALL frames. ## ## 2) Define & pack all widgets in the frames -- basically going through ## frames & their interiors in top-to-bottom and/or left-to-right order: ## ## 'fRsliders' - to contain 3 sliders - 'scale' wdigets. ## ## 'fRdepict' - to contain a canvas widget --- on which a circle ## is drawn; to depict the current angle. ## ## 'fRbuttons' - to contain several buttons and label & text widgets ## to display the current percent-of-circumference ## [0 to 100] and radians [ 0 to 6.28... ] and ## degrees [0 to 360]. ## ## 3) Define BINDINGS: none currently ## ## 4) Define PROCS: ## - 'angle_update' - for '-command' options on 3 RGB scales ## - 'draw_circle' ## - 'draw_angle' ## - 'put_vars' - for UseIt button ## - 'popup_msgVarWithScroll' - for Help button ## ## 5) Additional GUI INITIALIZATION: none, except for setting ## the HELPtext var for the Help button. ## ##+####################################################################### ## DEVELOPED WITH: ## Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october release, 'Karmic Koala'). ## ## $ wish ## % puts "$tcl_version $tk_version" ## showed 8.5 8.5 on Ubuntu 9.10 ## after Tcl-Tk 8.4 was replaced by 8.5 --- to get anti-aliased fonts. ##+######################################################################## ## MAINTENANCE HISTORY: ## This Tk script is based on a sample Tk script found at ## http://www.sci.usq.edu.au/~devoil/66309/tut2.html in 1999. ##------------------------------------------------------------------------ ## Created by: Blaise Montandon 2013aug09 Started on Ubuntu 9.10, based ## on the color-selector script ## of the FE (Freedom Environment) ## subsystems. Ref: www.freedomenv.com ## Changed by: Blaise Montandon 20....... ##+############################################################################ ##+################################# ## SET THE TOP WINDOW NAME. ##+################################# wm title . \ "tkAngle-Convert-Select - radians, degrees, percents-of-circumference-of-circle" wm iconname . "AngleSelect" # catch { wm title . "$env(FE_WIN_TITLE)" } # catch { wm iconname . "$env(FE_ICON_TITLE)" } ##+################################### ## SET THE TOP WINDOW POSITION. ##+################################### wm geometry . +15+30 # catch {eval wm geometry . "$env(FE_ANGLESEL_GEOM)" } ##+####################################################################### ## SET COLOR SCHEME (palette) FOR THE WINDOW. ##+####################################################################### if {0} { ## Grayish palette set Rpal255 210 set Gpal255 210 set Bpal255 210 } if {0} { ## Bluish palette set Rpal255 180 set Gpal255 180 set Bpal255 255 } if {0} { ## Greenish palette set Rpal255 180 set Gpal255 255 set Bpal255 180 } if {1} { ## Redish palette set Rpal255 255 set Gpal255 180 set Bpal255 180 } set hexCOLORpal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255] tk_setPalette $hexCOLORpal ## Set color background for some widgets. # set radbuttBKGD "#c0c0c0" # set chkbuttBKGD "#c0c0c0" # set listboxBKGD "#f0f0f0" # set entryBKGD "#f0f0f0" set textBKGD "#f0f0f0" ##+####################################################################### ## SET FONT VARS to use in the 'font create' statements below. ##+####################################################################### set FONTsize 14 set FONT_SMALLsize 12 ## For variable width: set FONT_varwidth \ " -family {comic sans ms} -size -$FONTsize -weight bold -slant roman " set FONT_SMALL_varwidth \ " -family {comic sans ms} -size -$FONT_SMALLsize -weight normal -slant roman " ## For fixed width: set FONT_fixedwidth \ " -family {dejavu sans mono} -size -$FONTsize -weight bold -slant roman " set FONT_SMALL_fixedwidth \ " -family {dejavu sans mono} -size -$FONT_SMALLsize -weight normal -slant roman " ##+##################################################################### ## DEFINE (temporary) 'font create' NAMES to be used ## in '-font' widget specs below. ##+##################################################################### eval font create fontTEMP_button $FONT_varwidth eval font create fontTEMP_label $FONT_varwidth eval font create fontTEMP_scale $FONT_varwidth # eval font create fontTEMP_entry $FONT_fixedwidth # eval font create fontTEMP_listbox $FONT_fixedwidth # eval font create fontTEMP_msg $FONT_fixedwidth eval font create fontTEMP_text $FONT_fixedwidth eval font create fontTEMP_varwidth $FONT_varwidth eval font create fontTEMP_fixedwidth $FONT_fixedwidth # eval font create fontTEMP_SMALL_button $FONT_SMALL_varwidth # eval font create fontTEMP_SMALL_label $FONT_SMALL_varwidth # eval font create fontTEMP_SMALL_scale $FONT_SMALL_varwidth # eval font create fontTEMP_SMALL_entry $FONT_SMALL_fixedwidth # eval font create fontTEMP_SMALL_listbox $FONT_SMALL_fixedwidth # eval font create fontTEMP_SMALL_msg $FONT_SMALL_fixedwidth # eval font create fontTEMP_SMALL_text $FONT_SMALL_fixedwidth # eval font create fontTEMP_SMALL_varwidth $FONT_SMALL_varwidth # eval font create fontTEMP_SMALL_fixedwidth $FONT_SMALL_fixedwidth ##+####################################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. padx,pady for buttons) ##+####################################################################### ## For BUTTON widgets: set fePADY_button 0 set fePADX_button 0 set feBDwidth_button 2 ## For LABEL widgets: set PADXpx_label 0 set PADYpx_label 0 # set feBDwidth_label 2 set BDwidthPx_label 2 ## SCALE geom parameters: set BDwidthPx_scale 2 set initScaleLengthPx 300 set scaleWidthPx 10 ## CANVAS geom parms: set initCanWidthPx 200 set initCanHeightPx 200 set minCanHeightPx 24 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 ## For TEXT widgets: set feBDwidth_text 2 ## For ENTRY widgets: # set feBDwidth_entry 2 ## For LISTBOX widgets: # set feBDwidth_listbox 2 ## For MESSAGE widgets: # set feBDwidth_msg 2 ##+################################################################### ## Set a MINSIZE of the window (roughly). (OR fix the window size.) ## ## For WIDTH, allow for a minwidth of the '.fRbuttons' frame: ## about 5 buttons (Exit,Clear,Fill,Outline,ColorBkgnd), and ## NOT a label widget showing current color info. ## ## For HEIGHT, allow ## 2 chars high for the '.fRbuttons' frame ## 1 char high for the '.fRobjects' frame ## 1 char high for the '.fRobjopts' frame ## 1 char high for the '.fRmodes' frame (if implemented) ## 1 char high for the '.fRmodeopts' frame (if implemented), ## 24 pixels high for the '.fRcanvas' frame. ##+####################################################################### ## We allow the window to be resizable and we pack the canvas with ## '-fill both -expand 1' so that the canvas can be enlarged by ## enlarging the window. # set minWinWidthPx [font measure fontTEMP_varwidth \ # " UseIt Cancel Help Percent: 0.500 Degrees: 180 Radians: 3.14159"] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), about 8 widgets x 4 pixels/widget for borders/padding ## for 8 widgets --- buttons and labels. # set minWinWidthPx [expr {40 + $minWinWidthPx}] ## MIN HEIGHT --- ## 6 chars high for the '.fRsliders' frame ## 1 char high for the '.fRbuttons' frame # set CharHeightPx [font metrics fontTEMP_varwidth -linespace] # set minWinHeightPx [expr {7 * $CharHeightPx}] ## Add about 28 pixels for top-bottom window decoration, ## about 4 frames x 4 pixels/frame for each of the 4 stacked frames/widgets ## and their widgets (their borders/padding). # set minWinHeightPx [expr {44 + $minWinHeightPx}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" # wm minsize . $minWinWidthPx $minWinHeightPx ##+############################################# ## If you want to make the window un-resizable, ## you can use the following statement. ##+############################################# wm resizable . 0 0 ##+######################################################################## ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+######################################################################## ## if { "$VARlocale" == "en"} ## For '.fRsliders' frame: set aRtext(labelSCALEdeg) "Degrees:" set aRtext(labelSCALErad) "Radians:" set aRtext(labelSCALEpcnt) "Percent:" ## For '.fRbuttons' frame: set aRtext(buttonUSEIT) "UseIt" set aRtext(buttonCANCEL) "Cancel" set aRtext(buttonHELP) "Help" set aRtext(labelTEXTdeg) " Degrees:" set aRtext(labelTEXTrad) " Radians:" set aRtext(labelTEXTpcnt) " Percent-of-circle-circumference:" ## END OF if { "$VARlocale" == "en" ##+######################################################################## ## ## GET INPUT PARM VALUE -- ## i.e. set ANGdeg from ## ## 1) an argument passed to this script ## OR ## 2) environment var ANG_DEG ## ##+######################################################################## ##+######################################################################## ## Example argc/argv processing: ## ## if {$argc == 0} { ## set VARtext "$env(CONFIRM_TEXT)" ## } else { ## set VARtext [lindex $argv 0] ## } ##+######################################################################## set twopi [expr {8.0 * atan(1.0)}] if {$argc == 1} { set ANGdeg [lindex $argv 0] } else { set ANGdeg 0 catch { set ANGdeg "$env(ANG_DEG)" } } set ANGpcnt [expr {$ANGdeg / 3.60}] set ANGrad [expr {($ANGpcnt/100.0) * $twopi}] ##+#################################################################### ## DEFINE *ALL* THE FRAMES: ## TOP-LEVEL FRAMES: ## - 'fRsliders' - to contain 3 sliderbars. ## - 'fRdepict' - to contain only its background; to display ## the color specified by the sliderbar settings. ## - 'fRbuttons' - to contain several buttons (UseIt,Cancel,etc), ## as well as 2 label & 2 text widgets to ## display the current per-cent and ## hex RGB-values of the color. ## ## 'fRsliders' & 'fRdepict' are packed on left & right. ## ## SUB-FRAMES: ## - 'fRsliders.fRdeg' (to contain 1 label, 1 sliderbar) ## - 'fRsliders.fRrad' (to contain 1 label, 1 sliderbar) ## - 'fRsliders.fRpcnt' (to contain 1 label, 1 sliderbar) ##+#################################################################### ## FOR TESTING: (like expansion of frames, during window expansion) # set feRELIEF_frame raised # set feBDwidth_frame 2 set feRELIEF_frame flat set feBDwidth_frame 0 frame .fRsliders -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRdepict -relief raised -borderwidth 2 frame .fRbuttons -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRsliders.fRdeg -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRsliders.fRrad -relief $feRELIEF_frame -borderwidth $feBDwidth_frame frame .fRsliders.fRpcnt -relief $feRELIEF_frame -borderwidth $feBDwidth_frame ##+######################################################## ## PACK *ALL* the FRAMES. ##+######################################################## pack .fRbuttons \ -side bottom \ -anchor w \ -fill x \ -expand 0 ##+########################################## ## NOTE: ## We need to pack the 'bottom' 'fRbuttons' ## frame before the 'fRsliders' & 'fRdepict' ## frames -- otherwise the 'bottom' ## frame comes out in the lower-right ## of the window, instead of below ## 'fRsliders' & 'fRdepict'. ## ## Alternatively, we could define an additional ## frame to contain the 'fRsliders' & 'fRdepcit' ## frames. ##+########################################## pack .fRsliders \ -side left \ -anchor w \ -fill both \ -expand 1 pack .fRdepict \ -side left \ -anchor w \ -fill both \ -expand 1 pack .fRsliders.fRdeg \ .fRsliders.fRrad \ .fRsliders.fRpcnt \ -side top \ -anchor w \ -fill x \ -expand 1 ##+################################################################ ## The frames are now defined and packed. ##+################################################################ ## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. ##+################################################################ ##+################################################################ ##+######################################################## ## IN THE 'fRsliders' frame -- DEFINE 3 LABEL and ## 3 SCALE widgets. THEN PACK THEM. ##+######################################################## ## DEGREES: label .fRsliders.fRdeg.label \ -text "$aRtext(labelSCALEdeg)" \ -font fontTEMP_label \ -width 8 \ -justify left \ -anchor w \ -relief flat \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label scale .fRsliders.fRdeg.scale \ -orient horizontal \ -from 0.0 -to 360.0 \ -resolution 0.1 \ -digits 4 \ -length 350px \ -variable ANGdeg \ -font fontTEMP_scale \ -showvalue true \ -bd $BDwidthPx_scale \ -width 10px ## -command {angle_update} .fRsliders.fRdeg.scale set $ANGdeg ## RADIANS: label .fRsliders.fRrad.label \ -text "$aRtext(labelSCALErad)" \ -font fontTEMP_label \ -width 8 \ -justify left \ -anchor w \ -relief flat \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label scale .fRsliders.fRrad.scale \ -orient horizontal \ -from 0.0 -to 6.283 \ -resolution 0.01 \ -digits 4 \ -length 350px \ -variable ANGrad \ -font fontTEMP_scale \ -showvalue true \ -bd $BDwidthPx_scale \ -width 10px ## -command {angle_update} .fRsliders.fRrad.scale set $ANGrad ## PERCENT-OF-CIRCUMFERENCE: label .fRsliders.fRpcnt.label \ -text "$aRtext(labelSCALEpcnt)" \ -font fontTEMP_label \ -width 8 \ -justify left \ -anchor w \ -relief flat \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label scale .fRsliders.fRpcnt.scale \ -orient horizontal \ -from 0.0 -to 100.0 \ -resolution 0.1 \ -digits 4 \ -length 350px \ -variable ANGpcnt \ -font fontTEMP_scale \ -showvalue true \ -bd $BDwidthPx_scale \ -width 10px ## -command {angle_update} .fRsliders.fRpcnt.scale set $ANGpcnt ##+################################################# ## PACK 3 LABELS & 3 SCALES IN 'fRsliders' FRAME. ##+################################################# pack .fRsliders.fRdeg.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliders.fRdeg.scale \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRsliders.fRrad.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliders.fRrad.scale \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRsliders.fRpcnt.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliders.fRpcnt.scale \ -side left \ -anchor w \ -fill x \ -expand 1 ##+###################################################### ## In the '.fRdepict' frame - ## DEFINE-and-PACK 1 CANVAS widget. ##+###################################################### ## We set '-highlightthickness' and '-borderwidth' to ## zero, to avoid covering some of the viewable area ## of the canvas, as suggested on page 558 of the 4th ## edition of 'Practical Programming with Tcl and Tk'. ##+################################################### canvas .fRdepict.can \ -width $initCanWidthPx \ -height $initCanHeightPx \ -relief flat \ -highlightthickness 0 \ -borderwidth 0 \ pack .fRdepict.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+######################################################## ## IN THE 'fRbuttons' frame -- DEFINE several BUTTONS --- ## 1 'UseIt' BUTTON, 1 'Cancel' BUTTON, ## 1 'Help' BUTTON, and ## 3 TEXT WIDGET (rather than a label or message widget, ## so that it is possible to paste the text values ## to another window), each with a label widget. ## THEN PACK THE WIDGETS. ##+######################################################## button .fRbuttons.buttUSEIT \ -text "$aRtext(buttonUSEIT)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {put_vars} button .fRbuttons.buttCANCEL \ -text "$aRtext(buttonCANCEL)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {exit} button .fRbuttons.buttHELP \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_button \ -padx $fePADX_button \ -pady $fePADY_button \ -relief raised \ -bd $feBDwidth_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext"} ## Provide label-and-text widgets for the angle values ## in several different units. set widthChars 10 set widthFiller " " ## DEGREES: label .fRbuttons.labTEXTdeg \ -text "$aRtext(labelTEXTdeg)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -relief flat \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label text .fRbuttons.txtANGdeg \ -relief raised \ -borderwidth $feBDwidth_text \ -height 1 \ -width $widthChars \ -wrap none \ -font fontTEMP_text ## RADIANS: label .fRbuttons.labTEXTrad \ -text "$aRtext(labelTEXTrad)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -relief flat \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label text .fRbuttons.txtANGrad \ -relief raised \ -borderwidth $feBDwidth_text \ -height 1 \ -width $widthChars \ -wrap none \ -font fontTEMP_text ## PERCENT: label .fRbuttons.labTEXTpcnt \ -text "$aRtext(labelTEXTpcnt)" \ -font fontTEMP_label \ -justify left \ -anchor w \ -relief flat \ -padx $PADXpx_label \ -pady $PADYpx_label \ -bd $BDwidthPx_label text .fRbuttons.txtANGpcnt \ -relief raised \ -borderwidth $feBDwidth_text \ -height 1 \ -width $widthChars \ -wrap none \ -font fontTEMP_text ## Pack the widgets in frame '.fRbuttons'. pack .fRbuttons.buttUSEIT \ .fRbuttons.buttCANCEL \ .fRbuttons.buttHELP \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.txtANGpcnt \ .fRbuttons.labTEXTpcnt \ .fRbuttons.txtANGrad \ .fRbuttons.labTEXTrad \ .fRbuttons.txtANGdeg \ .fRbuttons.labTEXTdeg \ -side right \ -anchor e \ -fill none \ -expand 0 ##+####################################### ## END OF MAIN SECTION TO SETUP THE GUI. ## FRAMES AND WIDGETS ARE DEFINED. ##+####################################### ##+##################################################################### ##+##################################################################### ## BINDINGS section: none (or 3 bindings on button1-release on the sliders) ##+##################################################################### ##+##################################################################### bind .fRsliders.fRdeg.scale {set TYPEchanged "DEG" ; angle_update 0} bind .fRsliders.fRrad.scale {set TYPEchanged "RAD" ; angle_update 0} bind .fRsliders.fRpcnt.scale {set TYPEchanged "PCNT" ; angle_update 0} ##+##################################################################### ##+##################################################################### ## PROCS section: ## - 'angle_update' ## - 'draw_circle' ## - 'draw_angle' ## - 'put_vars' ## - 'popup_msgVarWithScroll' ##+##################################################################### ##+##################################################################### ##+##################################################################### ## 'angle_update' PROCEDURE ##+##################################################################### ## PURPOSE: As any slider is changed, set ## 1) the other sliders ## 2) update the text widgets that hold the angle in 3 units ## 3) update the angle on the circle on the canvas ## ## CALLED BY: 3 scale widgets: ## - .fRsliders.fRdeg.scale ## - .fRsliders.fRrad.scale ## - .fRsliders.fRpcnt.scale ##+##################################################################### proc angle_update {x} { global TYPEchanged ANGdeg ANGrad ANGpcnt twopi widthChars widthFiller # global Rpal255 Gpal255 Bpal255 if {"$TYPEchanged" == "DEG"} { set ANGdeg [.fRsliders.fRdeg.scale get] set ANGpcnt [expr {$ANGdeg / 3.60}] set ANGrad [expr {$twopi * ($ANGpcnt/100.0)}] } if {"$TYPEchanged" == "RAD"} { set ANGrad [.fRsliders.fRrad.scale get] set ANGpcnt [expr {100.0 * $ANGrad / $twopi}] set ANGdeg [expr {$ANGpcnt * 3.60}] } if {"$TYPEchanged" == "PCNT"} { set ANGpcnt [.fRsliders.fRpcnt.scale get] set ANGrad [expr {($ANGpcnt/100.0) * $twopi}] set ANGdeg [expr {$ANGpcnt * 3.60}] } ## Update the angle on the canvas. redraw_angle $ANGdeg ## Show the current angle in DEGREES in a small text widget. .fRbuttons.txtANGdeg delete 1.0 end .fRbuttons.txtANGdeg insert 1.0 "$widthFiller" set insertIDX [expr {$widthChars - [string length "$ANGdeg"]}] .fRbuttons.txtANGdeg insert 1.$insertIDX $ANGdeg ## FOR TESTING: # puts "insertIDX: $insertIDX" ## Show the current angle in RADIANS in a small text widget. .fRbuttons.txtANGrad delete 1.0 end .fRbuttons.txtANGrad insert 1.0 "$widthFiller" set insertIDX [expr {$widthChars - [string length "$ANGrad"]}] .fRbuttons.txtANGrad insert 1.$insertIDX $ANGrad ## FOR TESTING: # puts "insertIDX: $insertIDX" ## Show the current angle in PERCENTS in a small text widget. .fRbuttons.txtANGpcnt delete 1.0 end .fRbuttons.txtANGpcnt insert 1.0 "$widthFiller" set insertIDX [expr {$widthChars - [string length "$ANGpcnt"]}] .fRbuttons.txtANGpcnt insert 1.$insertIDX $ANGpcnt ## FOR TESTING: # puts "insertIDX: $insertIDX" } ## END of proc 'angle_update' ##+##################################################################### ## 'draw_circle' PROCEDURE ##+##################################################################### ## ## PURPOSE: To draw a circle in the middle of the canvas. ## ## CALLED: in the 'Additional GUI Initialization' section at the ## bottom of this script. ##+##################################################################### proc draw_circle {} { # global ## Get the current width & height of the canvas (in pixels). set canWidthPx [winfo width .fRdepict.can] set canHeightPx [winfo height .fRdepict.can] ## FOR TESTING: # puts "canWidthPx : $canWidthPx" # puts "canHeightPx: $canHeightPx" set ULXpx [expr {0.1 * $canWidthPx }] set ULYpx [expr {0.1 * $canHeightPx}] set LRXpx [expr {0.9 * $canWidthPx }] set LRYpx [expr {0.9 * $canHeightPx}] ## FOR TESTING: # puts "ULXpx: $ULXpx" # puts "ULYpx: $ULYpx" # puts "LRXpx: $LRXpx" # puts "LRYpx: $LRYpx" .fRdepict.can create oval \ $ULXpx $ULYpx $LRXpx $LRYpx \ -width 2 -outline black ## -fill black } ## END of proc 'draw_circle' ##+##################################################################### ## 'redraw_angle' PROCEDURE ##+##################################################################### ## ## PURPOSE: To (re)draw an angle on the circle in the middle of the canvas. ## ## CALLED BY: the 'angle_update' proc ##+##################################################################### proc redraw_angle {degrees} { ## Get the current width & height of the canvas (in pixels). set canWidthPx [winfo width .fRdepict.can] set canHeightPx [winfo height .fRdepict.can] ## FOR TESTING: # puts "canWidthPx : $canWidthPx" # puts "canHeightPx: $canHeightPx" set ULXpx [expr {0.1 * $canWidthPx }] set ULYpx [expr {0.1 * $canHeightPx}] set LRXpx [expr {0.9 * $canWidthPx }] set LRYpx [expr {0.9 * $canHeightPx}] .fRdepict.can delete TAGarc ## FOR TESTING: # puts "ULXpx: $ULXpx" # puts "ULYpx: $ULYpx" # puts "LRXpx: $LRXpx" # puts "LRYpx: $LRYpx" .fRdepict.can create arc \ $ULXpx $ULYpx $LRXpx $LRYpx -start 0 -extent $degrees \ -width 2 -fill black -outline black -tag TAGarc } ## END of proc 'redraw_angle' ##+##################################################################### ## PROCEDURE -- put_vars ## ## PURPOSE: Puts a string containing the 3 angles (ANGdeg, ANGrad, ANGpcnt) ## to standard output. Then exits this GUI. ## ## Called by: button .fRbuttons.buttOK ##+##################################################################### proc put_vars { } { global ANGdeg ANGrad ANGpcnt puts "$ANGdeg $ANGrad $ANGpcnt" exit } ## END of proc 'puts_vars' ##+######################################################################## ## PROC 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext } { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 wm geometry $toplevName +100+50 wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+############################################### ## END OF PROCS SECTION. ##+############################################### ## Setting of HELPtext variable follows. ##+############################################### set HELPtext \ " **** HELP for this 'tkAngle-Convert-Select' GUI utility **** **** for angles in **** **** radians, degrees, or percent-of-circumference **** This Tk script provides a GUI for showing angles between zero and 360 degrees in three different units: - degrees - radians - percents of the circumference of a circle. These 3 different units are shown (and selected for conversion to the other 2 units) via 3 'sliders' of 3 Tk 'scale' widgets. These 3 different (corresponding) numbers are also shown in 3 'text' widgets, a few characters wide --- from which a user can copy-and-paste the numbers from this GUI window to some other window. For any 'slider' change, this GUI script IMMEDIATELY updates the location of the other 2 'sliders' --- and the current angle is depicted on a circle drawn in a 'canvas' wdiget in a corner of the GUI window (covering about 20% of the window). The 3 text widgets, that show the angle in the 3 different units, are also IMMEDIATELY updated whenever any one of the 3 scale widget 'sliders' is changed. By clicking on a 'UseIt' button on the GUI, this script returns a string containing the current angle (in the 3 different units) to a calling script/application. INITIALIZING THE ANGLE: This script will accept an angle (in degrees) which is used to initialize the - setting of the 3 'sliders' - the numbers shown in the 3 small text widgets - the display of an angle in a circle on the canvas widget. The angle can be passed to the script as an argument --- OR, if some 'catch' statements in the script are de-commented --- the angle can be passed as an environment variable. FINE ADJUSTMENTS OF THE SCALES: It is typically not obvious to a user who has not used the Tk scale widget before that one can easily advance the 'slider' one resolution-unit at a time. You can mouse-click ON EITHER SIDE OF the slider 'button' to advance the slider one resolution-unit per click. Simply click repeatedly to adjust the slider to a specific value. AND, by clicking on either side and HOLDING DOWN, the slider will rapidly advance one resolution-unit at a time UNTIL the mouse-button is RELEASED. SOME USES of this utility: 1) Useful for helping math-science students get a visual 'feel' for the relation between radians and degrees and the distance around the circumference of a circle. 2) Also could be useful for programmers (example: Tcl-Tk programmers) for determining angles (example: radians) to be used in various Tcl-Tk apps --- example: Tk apps doing 'create arc' commands on a Tk 'canvas'. 3) IN A SHELL SCRIPT OR ANOTHER TK SCRIPT, this Tk script can ACT AS AN ANGLE SELECTOR by passing the current angle (in the 3 different units) to 'stdout', when the 'UseIt' button is clicked. Example output string: 180.0 3.14159 0.5 (When the 'Cancel' button is clicked, the GUI is closed WITHOUT sending a text string to 'stdout'.) Note: The user can set up this script as an icon on a desktop so that the GUI can be started up by a click (or two) on the icon. " ##+############################################### ## ADDITONAL GUI INITIALIZATION (if any) FOLLOWS. ##+############################################### update draw_circle set TYPEchanged "DEG" angle_update 0